


#ifdef __WIN32__

#include "../vcd-ping.h"
#include "../vcd-conf/vcd-conf.h"
#include "../vcd-log.h"

#include <windows.h>

typedef struct st_vcd_ping_ctx{
    VCD_PING_CALLBACK func;
    GThread *thd;
    gpointer priv;
    gboolean bStop;
}VcdPingWin32Ctx;

static VcdPingWin32Ctx* g_ping_ctx;

static void vcd_ping_win32_stop();
/*
Ping statistics for 192.168.32.50:
    Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),

ReadFile read:97 buff:Approximate round trip times in milli-seconds:
    Minimum = 0ms, Maximum = 0ms, Average = 0ms
*/

// 4 packets transmitted, 4 received, 0% packet loss, time 3072ms
static gboolean is_packet_loss_str(const char* data){
    if(!data) return FALSE;

    const char* sub = "Lost = ";
    if(strstr(data,sub)){
        return TRUE;
    }
    return FALSE;
}
// rtt min/avg/max/mdev = 0.578/0.598/0.625/0.019 ms
static gboolean is_avg_delay_str(const char* data){
    if(!data) return FALSE;

    const char* sub = "Average = ";
    if(strstr(data,sub)){
        return TRUE;
    }
    return FALSE;
}

// Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
static int find_packet_loss(const char* data){

    if(!is_packet_loss_str(data)){
        goto fail;
    }

    const char* sub = " Lost = ";
    char* pStar = strstr(data,sub);
    if(!pStar) goto fail;

    pStar += strlen(sub);

    char* pEnd  = strstr(pStar,"(");
    if(!pEnd)  goto fail;

    char tmp[10] = {0};
    strncpy(tmp,pStar,pEnd-pStar);

    int loss = atoi(tmp);
    return loss;
fail:
    return -1;
}
//  Minimum = 0ms, Maximum = 0ms, Average = 0ms
static float find_avg_delay(const char* data){
    if(!is_avg_delay_str(data)){
        goto fail;
    }

    const char* sub = "Average = ";
    char* pStar = strstr(data,sub);
    if(!pStar) goto fail;

    pStar += strlen(sub);

//    pStar = strstr(pStar,"ms");
//    if(!pStar) goto fail;

//    // 0.598/0.625/0.019 ms
//    pStar = pStar + 1;

    char* pEnd  = strstr(pStar,"ms");
    if(!pEnd)  goto fail;

    char tmp[10] = {0};
    strncpy(tmp,pStar,pEnd-pStar);

    float delay = atof(tmp);

    return delay;
fail:
    return -1;
}

static gpointer GThreadFunc_ping(gpointer arg){

    while(g_ping_ctx && !g_ping_ctx->bStop){

        char* host = g_vcd_conf->ip;
        if(!host) goto fail;

        char cmd[100] = {0};
        snprintf(cmd, sizeof(cmd), "cmd.exe /c chcp 437 && ping -n 2 -w 1000 %s", host);

        SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
        HANDLE hRead, hWrite;
        if (!CreatePipe(&hRead, &hWrite, &sa, 0)){
                goto fail;
        }
        // 设置命令行进程启动信息(以隐藏方式启动命令并定位其输出到hWrite
        STARTUPINFO si = { sizeof(STARTUPINFO) }; // Pointer to STARTUPINFO structure;
        GetStartupInfo(&si);
        si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
        //si.dwFlags = STARTF_USESHOWWINDOW;
        si.wShowWindow = SW_HIDE; //隐藏窗口；
        si.hStdError = hWrite;
        si.hStdError = hWrite;
        si.hStdOutput = hWrite; //管道的输入端口连接命令行的输出；
        // 启动命令行
        PROCESS_INFORMATION pi;// Pointer to PROCESS_INFORMATION structure;
        if (!CreateProcess(NULL,
            cmd,
            NULL,
            NULL,
            TRUE,
            //FALSE,          // Set handle inheritance to FALSE
            NULL,
            //0,              // No creation flags
            NULL,
            NULL,
            &si,
            &pi)){
            goto fail;
        }
        CloseHandle(hWrite);//关闭管道的输入端口；

        // 读取命令行返回值
        const int len = 1024;
        char data[1024] = {0};

        int loss = -1;
        float delay = -1;

        DWORD dwRead = 0;
        while (ReadFile(hRead, data, len, &dwRead, NULL))//从管道的输出端获取命令行写入的数据；
        {
            if(is_packet_loss_str(data))
                loss = find_packet_loss(data);
            if(is_avg_delay_str(data))
                delay = find_avg_delay(data);

             printf("ReadFile read:%d buff:%s\n",dwRead,data);
             if(loss != -1 && delay != -1 && g_ping_ctx && g_ping_ctx->func){

                 if(is_packet_loss_str(data))
                     loss = find_packet_loss(data);
                 if(is_avg_delay_str(data))
                     delay = find_avg_delay(data);

                 StVcdPingVar ctx = {0};
                 ctx.delay = delay;
                 ctx.pkt_loss_rate = loss;
                 ctx.priv = g_ping_ctx->priv;
                 g_ping_ctx->func(&ctx);
             }
        }
        CloseHandle(hRead);//关闭管道的输出端口；
        continue;
fail:
        Sleep(1000);
        continue;
    }
    return FALSE;
}


static gboolean vcd_ping_win32_start(VCD_PING_CALLBACK func,gpointer priv){

    vcd_ping_win32_stop();

    M_DEBUG("vcd_ping_win32_start");
    g_ping_ctx = g_malloc0(sizeof(VcdPingWin32Ctx));

    g_ping_ctx->priv = priv;
    g_ping_ctx->func = func;

    g_ping_ctx->thd = g_thread_new("vcd_ping_win32", (GThreadFunc)GThreadFunc_ping, NULL);

    return TRUE;
}


static void vcd_ping_win32_stop(){
    g_return_if_fail(g_ping_ctx != 0);
    M_DEBUG("vcd_ping_win32_stop");

    g_ping_ctx->bStop = TRUE;

//    system("killall ping");

    g_thread_join(g_ping_ctx->thd);

    g_free(g_ping_ctx);
    g_ping_ctx = 0;
}


struct StVcdPingCtx g_vcd_ping_win32 = {
    .start        = vcd_ping_win32_start,
    .stop         = vcd_ping_win32_stop
};


#endif
